/******************************************************/
/* Goblin's Cube - Rubik's cube game for Wii Homebrew */
/* Copyright (C) 2009 Ricardo Bueno Cordeiro          */
/* Licensed under de GNU General Public License v2.0  */
/*   See license_gplv2.txt for detalis                */
/******************************************************/

#include <stdio.h>

#include <gccore.h>

#include <FreeTypeGX.h>
#include "font_ttf.h"

#include "textures.h"
#include "textures_tpl.h"

#include "draw.h"

static GXTexObj cube_texture;
static GXTexObj hand_texture;

// State
static Mtx current_view;
static Mtx current_model;

// 3D
static Mtx44 perspective;
static Mtx view;

// 2D (text only)
static Mtx text_view;
static Mtx text_model;
static Mtx44 text_proj;

// Font
static FreeTypeGX *freeTypeGX;


void _DR_setCurrentModelViewMtx() {
	Mtx modelview;
	guMtxConcat(current_view, current_model, modelview);
	GX_LoadPosMtxImm(modelview, GX_PNMTX0);
	GX_LoadNrmMtxImm(modelview, GX_PNMTX0);
}

void DR_getCurrentViewMtx(Mtx m) {
	guMtxCopy(current_view, m);
}

void DR_setCurrentViewMtx(Mtx m) {
	guMtxCopy(m, current_view);
	_DR_setCurrentModelViewMtx();
}

void DR_getCurrentModelMtx(Mtx m) {
	guMtxCopy(current_model, m);
}

void DR_setCurrentModelMtx(Mtx m) {
	guMtxCopy(m, current_model);
	_DR_setCurrentModelViewMtx();
}

void DR_set_cube_texture() {
	GX_LoadTexObj(&cube_texture, GX_TEXMAP0);
	GX_Flush();
}

void DR_set_hand_texture() {
	GX_LoadTexObj(&hand_texture, GX_TEXMAP0);
	GX_Flush();
}

void DR_load_textures() {
	TPLFile file_tpl;
	TPL_OpenTPLFromMemory(&file_tpl, (void *)textures_tpl, textures_tpl_size);
	TPL_GetTexture(&file_tpl, cubetex, &cube_texture);
	TPL_GetTexture(&file_tpl, handtex, &hand_texture);
	DR_set_cube_texture();
}

void DR_load_font() {
	freeTypeGX = new FreeTypeGX(GX_TF_RGBA8, GX_POS_XYZ);
	freeTypeGX->loadFont(font_ttf, font_ttf_size, 32);
}

void DR_init(int text_width, int text_height, f32 aspect_ratio) {
	DR_load_textures();
	DR_load_font();

	// Set up projection matrix
	guPerspective(perspective, 45, aspect_ratio, 0.1F, 300.0F);
	guOrtho(text_proj, text_width, 0, 0, text_height, -1000, 1000);

	// Set up view matrix
	Vector pos = {0.0, 0.0, 0.0};
	Vector front = {0.0, 0.0, -1.0};
	Vector up = {0.0, 1.0, 0.0};
	guLookAt(view, &pos, &up, &front);
	guMtxIdentity(text_view);

	// Set up text model
	guMtxIdentity(text_model);
	text_model[1][1] = -1.0;
}

void DR_configure_text() {
	GX_LoadProjectionMtx(text_proj, GX_ORTHOGRAPHIC);
	DR_setCurrentViewMtx(text_view);
	DR_setCurrentModelMtx(text_model);

	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);

	GX_SetChanCtrl(GX_COLOR0A0,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHT0,GX_DF_CLAMP, GX_AF_SPOT);

	GX_SetCullMode(GX_CULL_NONE);

	GX_SetZMode(GX_DISABLE, GX_LEQUAL, GX_FALSE);

	GX_Flush();
}

void DR_configure_draw() {
	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_NRM, GX_DIRECT);
 	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);

	GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL);

	GX_LoadProjectionMtx(perspective, GX_PERSPECTIVE);
	DR_setCurrentViewMtx(view); 

	GX_SetChanCtrl(GX_COLOR0A0,GX_ENABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHT0,GX_DF_CLAMP, GX_AF_SPOT);

	GX_SetZMode(GX_ENABLE, GX_LEQUAL, GX_TRUE);

	GX_Flush();
}

void DR_draw_text(int x, int y, GXColor c, const char *s, ...) {
	va_list ap;
	char line[LARGEST_DRAWABLE_TEXT];
	wchar_t line_wchar[LARGEST_DRAWABLE_TEXT];

	va_start(ap, s);
	vsnprintf(line, LARGEST_DRAWABLE_TEXT, s, ap);
	va_end(ap);

	char *src = line;
	wchar_t *dst = line_wchar;
	while((*dst++ = *src++));

	freeTypeGX->drawText(x, -y, line_wchar, c);
}

void DR_draw_text(int x, int y, GXColor c, u16 style, const char *s, ...) {
	va_list ap;
	char line[LARGEST_DRAWABLE_TEXT];
	wchar_t line_wchar[LARGEST_DRAWABLE_TEXT];

	va_start(ap, s);
	vsnprintf(line, LARGEST_DRAWABLE_TEXT, s, ap);
	va_end(ap);

	char *src = line;
	wchar_t *dst = line_wchar;
	while((*dst++ = *src++));

	freeTypeGX->drawText(x, -y, line_wchar, c, style);
}
